-
Notifications
You must be signed in to change notification settings - Fork 11.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[PatternMatch] Add matchers for m_{I,F,}Cmp
and m_{I,F,}SpecificCmp
; NFC
#98282
Conversation
@llvm/pr-subscribers-llvm-ir Author: None (goldsteinn) ChangesThese matchers either take no predicate argument or match a specific We have a lot of cases where the Pred argument is either unused and Likewise we have a lot of cases where we only pass in Pred to test Full diff: https://github.com/llvm/llvm-project/pull/98282.diff 2 Files Affected:
diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index d4e355431a27a..f9f473fb4276e 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -1548,25 +1548,38 @@ template <typename T> inline Exact_match<T> m_Exact(const T &SubPattern) {
//
template <typename LHS_t, typename RHS_t, typename Class, typename PredicateTy,
- bool Commutable = false>
+ bool Commutable = false, bool MatchExistingPred = false>
struct CmpClass_match {
- PredicateTy &Predicate;
+ static_assert(!Commutable || !MatchExistingPred,
+ "Can't match predicate when using commutable matcher");
+
+ // Make predicate ty const ref if we are matching. Not strictly necessary but
+ // will cause a compilation warning if we accidentally try to set it with
+ // MatchExistingPred enabled.
+ using InternalPredTy =
+ std::conditional_t<MatchExistingPred, const PredicateTy &, PredicateTy &>;
+ InternalPredTy Predicate;
LHS_t L;
RHS_t R;
// The evaluation order is always stable, regardless of Commutability.
// The LHS is always matched first.
- CmpClass_match(PredicateTy &Pred, const LHS_t &LHS, const RHS_t &RHS)
+ CmpClass_match(InternalPredTy Pred, const LHS_t &LHS, const RHS_t &RHS)
: Predicate(Pred), L(LHS), R(RHS) {}
template <typename OpTy> bool match(OpTy *V) {
if (auto *I = dyn_cast<Class>(V)) {
if (L.match(I->getOperand(0)) && R.match(I->getOperand(1))) {
- Predicate = I->getPredicate();
- return true;
+ if constexpr (MatchExistingPred)
+ return I->getPredicate() == Predicate;
+ else {
+ Predicate = I->getPredicate();
+ return true;
+ }
} else if (Commutable && L.match(I->getOperand(1)) &&
R.match(I->getOperand(0))) {
- Predicate = I->getSwappedPredicate();
+ if constexpr (!MatchExistingPred)
+ Predicate = I->getSwappedPredicate();
return true;
}
}
@@ -1592,6 +1605,50 @@ m_FCmp(FCmpInst::Predicate &Pred, const LHS &L, const RHS &R) {
return CmpClass_match<LHS, RHS, FCmpInst, FCmpInst::Predicate>(Pred, L, R);
}
+template <typename LHS, typename RHS>
+inline CmpClass_match<LHS, RHS, CmpInst, CmpInst::Predicate>
+m_Cmp(const LHS &L, const RHS &R) {
+ CmpInst::Predicate Unused;
+ return CmpClass_match<LHS, RHS, CmpInst, CmpInst::Predicate>(Unused, L, R);
+}
+
+template <typename LHS, typename RHS>
+inline CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate>
+m_ICmp(const LHS &L, const RHS &R) {
+ ICmpInst::Predicate Unused;
+ return CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate>(Unused, L, R);
+}
+
+template <typename LHS, typename RHS>
+inline CmpClass_match<LHS, RHS, FCmpInst, FCmpInst::Predicate>
+m_FCmp(const LHS &L, const RHS &R) {
+ FCmpInst::Predicate Unused;
+ return CmpClass_match<LHS, RHS, FCmpInst, FCmpInst::Predicate>(Unused, L, R);
+}
+
+template <typename LHS, typename RHS>
+inline CmpClass_match<LHS, RHS, CmpInst, CmpInst::Predicate, false, true>
+m_SpecificCmp(const CmpInst::Predicate &MatchPred, const LHS &L, const RHS &R) {
+ return CmpClass_match<LHS, RHS, CmpInst, CmpInst::Predicate, false, true>(
+ MatchPred, L, R);
+}
+
+template <typename LHS, typename RHS>
+inline CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate, false, true>
+m_SpecificICmp(const ICmpInst::Predicate &MatchPred, const LHS &L,
+ const RHS &R) {
+ return CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate, false, true>(
+ MatchPred, L, R);
+}
+
+template <typename LHS, typename RHS>
+inline CmpClass_match<LHS, RHS, FCmpInst, FCmpInst::Predicate, false, true>
+m_SpecificFCmp(const FCmpInst::Predicate &MatchPred, const LHS &L,
+ const RHS &R) {
+ return CmpClass_match<LHS, RHS, FCmpInst, FCmpInst::Predicate, false, true>(
+ MatchPred, L, R);
+}
+
//===----------------------------------------------------------------------===//
// Matchers for instructions with a given opcode and number of operands.
//
@@ -2617,6 +2674,14 @@ m_c_ICmp(ICmpInst::Predicate &Pred, const LHS &L, const RHS &R) {
R);
}
+template <typename LHS, typename RHS>
+inline CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate, true>
+m_c_ICmp(const LHS &L, const RHS &R) {
+ ICmpInst::Predicate Unused;
+ return CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate, true>(Unused,
+ L, R);
+}
+
/// Matches a specific opcode with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline SpecificBinaryOp_match<LHS, RHS, true>
diff --git a/llvm/unittests/IR/PatternMatch.cpp b/llvm/unittests/IR/PatternMatch.cpp
index 9f91b4f3f9939..309fcc93996bc 100644
--- a/llvm/unittests/IR/PatternMatch.cpp
+++ b/llvm/unittests/IR/PatternMatch.cpp
@@ -2250,9 +2250,151 @@ TYPED_TEST(MutableConstTest, ICmp) {
ICmpInst::Predicate MatchPred;
EXPECT_TRUE(m_ICmp(MatchPred, m_Value(MatchL), m_Value(MatchR))
- .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
EXPECT_EQ(L, MatchL);
EXPECT_EQ(R, MatchR);
+
+ EXPECT_TRUE(m_Cmp(MatchPred, m_Value(MatchL), m_Value(MatchR))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+ EXPECT_EQ(L, MatchL);
+ EXPECT_EQ(R, MatchR);
+
+ EXPECT_TRUE(m_ICmp(m_Specific(L), m_Specific(R))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+
+ EXPECT_TRUE(m_Cmp(m_Specific(L), m_Specific(R))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+
+ EXPECT_FALSE(m_ICmp(m_Specific(R), m_Specific(L))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+ EXPECT_FALSE(m_Cmp(m_Specific(R), m_Specific(L))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+
+ EXPECT_TRUE(m_c_ICmp(m_Specific(R), m_Specific(L))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+
+ EXPECT_FALSE(m_c_ICmp(m_Specific(R), m_Specific(R))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+
+ EXPECT_TRUE(m_SpecificICmp(Pred, m_Specific(L), m_Specific(R))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+ EXPECT_TRUE(m_SpecificCmp(Pred, m_Specific(L), m_Specific(R))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+
+ EXPECT_FALSE(m_SpecificICmp(Pred, m_Specific(R), m_Specific(L))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+ EXPECT_FALSE(m_SpecificCmp(Pred, m_Specific(R), m_Specific(L))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+
+ MatchL = nullptr;
+ MatchR = nullptr;
+ EXPECT_TRUE(m_SpecificICmp(Pred, m_Value(MatchL), m_Value(MatchR))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+ EXPECT_EQ(L, MatchL);
+ EXPECT_EQ(R, MatchR);
+ MatchL = nullptr;
+ MatchR = nullptr;
+ EXPECT_TRUE(m_SpecificCmp(Pred, m_Value(MatchL), m_Value(MatchR))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+ EXPECT_EQ(L, MatchL);
+ EXPECT_EQ(R, MatchR);
+
+ EXPECT_FALSE(m_SpecificICmp(Pred, m_Specific(R), m_Specific(L))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+ EXPECT_FALSE(m_SpecificCmp(Pred, m_Specific(R), m_Specific(L))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+
+ EXPECT_FALSE(m_SpecificICmp(ICmpInst::getInversePredicate(Pred),
+ m_Specific(L), m_Specific(R))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+ EXPECT_FALSE(m_SpecificCmp(ICmpInst::getInversePredicate(Pred), m_Specific(L),
+ m_Specific(R))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+
+ EXPECT_FALSE(m_SpecificICmp(ICmpInst::getInversePredicate(Pred),
+ m_Value(MatchL), m_Value(MatchR))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+ EXPECT_FALSE(m_SpecificCmp(ICmpInst::getInversePredicate(Pred),
+ m_Value(MatchL), m_Value(MatchR))
+ .match((InstructionType)IRB.CreateICmp(Pred, L, R)));
+}
+
+TYPED_TEST(MutableConstTest, FCmp) {
+ auto &IRB = PatternMatchTest::IRB;
+
+ typedef std::tuple_element_t<0, TypeParam> ValueType;
+ typedef std::tuple_element_t<1, TypeParam> InstructionType;
+
+ Value *L = Constant::getNullValue(IRB.getFloatTy());
+ Value *R = ConstantFP::getInfinity(IRB.getFloatTy(), true);
+ FCmpInst::Predicate Pred = FCmpInst::FCMP_OGT;
+
+ ValueType MatchL;
+ ValueType MatchR;
+ FCmpInst::Predicate MatchPred;
+
+ EXPECT_TRUE(m_FCmp(MatchPred, m_Value(MatchL), m_Value(MatchR))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+ EXPECT_EQ(L, MatchL);
+ EXPECT_EQ(R, MatchR);
+
+ EXPECT_TRUE(m_Cmp(MatchPred, m_Value(MatchL), m_Value(MatchR))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+ EXPECT_EQ(L, MatchL);
+ EXPECT_EQ(R, MatchR);
+
+ EXPECT_TRUE(m_FCmp(m_Specific(L), m_Specific(R))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+
+ EXPECT_TRUE(m_Cmp(m_Specific(L), m_Specific(R))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+
+ EXPECT_FALSE(m_FCmp(m_Specific(R), m_Specific(L))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+ EXPECT_FALSE(m_Cmp(m_Specific(R), m_Specific(L))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+
+ EXPECT_TRUE(m_SpecificFCmp(Pred, m_Specific(L), m_Specific(R))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+ EXPECT_TRUE(m_SpecificCmp(Pred, m_Specific(L), m_Specific(R))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+
+ EXPECT_FALSE(m_SpecificFCmp(Pred, m_Specific(R), m_Specific(L))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+ EXPECT_FALSE(m_SpecificCmp(Pred, m_Specific(R), m_Specific(L))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+
+ MatchL = nullptr;
+ MatchR = nullptr;
+ EXPECT_TRUE(m_SpecificFCmp(Pred, m_Value(MatchL), m_Value(MatchR))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+ EXPECT_EQ(L, MatchL);
+ EXPECT_EQ(R, MatchR);
+ MatchL = nullptr;
+ MatchR = nullptr;
+ EXPECT_TRUE(m_SpecificCmp(Pred, m_Value(MatchL), m_Value(MatchR))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+ EXPECT_EQ(L, MatchL);
+ EXPECT_EQ(R, MatchR);
+
+ EXPECT_FALSE(m_SpecificFCmp(Pred, m_Specific(R), m_Specific(L))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+ EXPECT_FALSE(m_SpecificCmp(Pred, m_Specific(R), m_Specific(L))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+
+ EXPECT_FALSE(m_SpecificFCmp(FCmpInst::getInversePredicate(Pred),
+ m_Specific(L), m_Specific(R))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+ EXPECT_FALSE(m_SpecificCmp(FCmpInst::getInversePredicate(Pred), m_Specific(L),
+ m_Specific(R))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+
+ EXPECT_FALSE(m_SpecificFCmp(FCmpInst::getInversePredicate(Pred),
+ m_Value(MatchL), m_Value(MatchR))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
+ EXPECT_FALSE(m_SpecificCmp(FCmpInst::getInversePredicate(Pred),
+ m_Value(MatchL), m_Value(MatchR))
+ .match((InstructionType)IRB.CreateFCmp(Pred, L, R)));
}
TEST_F(PatternMatchTest, ConstExpr) {
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
…p`; NFC These matchers either take no predicate argument or match a specific predicate respectively. We have a lot of cases where the Pred argument is either unused and requiring the argument reduces code clarity. Likewise we have a lot of cases where we only pass in Pred to test equality which the new `*Specific*` helpers can simplify.
6d74dbe
to
8842117
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. We might also need m_c_SpecificICmp, but let's start with this.
Use after scope in the new test https://lab.llvm.org/buildbot/#/builders/169/builds/930 |
Hm yeah, the way the "unused predicate" case is implemented doesn't work ... the actual match will happen later, and at that point the dummy variable is out of scope. I guess we'd need a separate matcher class for that. |
@goldsteinn @nikic I temporarily disabled the test-case, please take a look. |
…p`; NFC These matchers either take no predicate argument or match a specific predicate respectively. We have a lot of cases where the Pred argument is either unused and requiring the argument reduces code clarity. Likewise we have a lot of cases where we only pass in Pred to test equality which the new `*Specific*` helpers can simplify. Closes llvm#98282
Introduced with llvm#98282
Introduced with llvm#98282
Fix at: #98866 |
…p`; NFC These matchers either take no predicate argument or match a specific predicate respectively. We have a lot of cases where the Pred argument is either unused and requiring the argument reduces code clarity. Likewise we have a lot of cases where we only pass in Pred to test equality which the new `*Specific*` helpers can simplify. Closes llvm#98282
Introduced with llvm#98282
Introduced with llvm#98282
These matchers either take no predicate argument or match a specific
predicate respectively.
We have a lot of cases where the Pred argument is either unused and
requiring the argument reduces code clarity.
Likewise we have a lot of cases where we only pass in Pred to test
equality which the new
*Specific*
helpers can simplify.